module top(
	input clk,
	input resetn,
	output trap,
	output reg [7:0] out_byte,
	output reg out_byte_en,
    output clk_o,
    output mem_valid_o,
    output mem_ready_o,
    output led,
    output uart_tx,
    input uart_rx,

    output psram_clk,
    inout [3:0] psram_dio,
    output psram_cs,

    output uart2_tx,
    input uart2_rx,
    input [3:0] key//
);
/*
*  CH340 RX ----- FPGA 30 TX
*  CH340 TX ----- FPGA 31 RX
*
*  WCH-LIN                   71 TX
*  WCH-LIN                   72 rx
*/
wire mem_valid;
wire mem_instr;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;

wire mem_ready;
wire [31:0] mem_rdata;

assign mem_valid_o = mem_valid;
assign mem_ready_o = mem_ready;

wire [31:0] riscv_pc;
wire cpu_reset;
riscv32 #(
		.STACKADDR(32'hffff_fff0)
	)picorv32_core(
	.clk      (clk      ),
    .resetn   (  resetn ),
    .trap     (  trap   ),
    .mem_valid(mem_valid),
    .mem_instr(mem_instr),
    .mem_ready(mem_ready),
    .mem_addr (mem_addr ),
    .mem_wdata(mem_wdata),
    .mem_wstrb(mem_wstrb),
    .mem_rdata(mem_rdata),
    .PC(riscv_pc),
    .irq({30'd0,~{key[1:0]}}),
    .cpu_reset(cpu_reset),
    .uart_tx(uart2_tx),
	.uart_rx(uart2_rx)
);

reg flag;
always @(posedge clk) begin
    flag <= ~flag;
end



reg mem_ready_r0;
wire mem_ready_r1;
reg [31:0] mem_rdata_r0;
wire [31:0] mem_rdata_r1;


wire [31:0] psram_rdata;
wire psram_ready;
wire psram_valid;

assign mem_ready = (mem_addr[31:16] == 16'h0) ? mem_ready_r1 : 
                ((mem_addr >= 32'h80_0000)&&(mem_addr < 32'h100_0000)) ? psram_ready : mem_ready_r0;
assign mem_rdata = (mem_addr[31:16] == 16'h0) ? mem_rdata_r1 :
                ((mem_addr >= 32'h80_0000)&&(mem_addr < 32'h100_0000)) ? psram_rdata : mem_rdata_r0;

uart_memory#(
	.CLK_FREQ	(27000000),
	.UART_BPS	(115200)
) uart_memory_u1(
    .clk(clk),
    .resetn(cpu_reset),
    .uart_rx(uart_rx),
    .uart_tx(uart_tx),
    .memory_en(1'b1),
    .mem_valid(mem_valid),
    .mem_instr(mem_instr),
    .mem_addr(mem_addr),
    .mem_wdata(mem_wdata),
    .mem_wstrb(mem_wstrb),
    .mem_rdata(mem_rdata_r1),
    .mem_ready(mem_ready_r1)
);


assign psram_valid = (mem_addr >= 32'h80_0000)&&(mem_addr < 32'h100_0000) && 
                    ((mem_valid == 1'b1)||(mem_instr == 1'b1));

psram psram_u0(
    .clk(clk),
    .resetn(resetn),

    .psram_clk(psram_clk),
    .psram_dio(psram_dio),
    .psram_cs(psram_cs),

    .mem_addr(mem_addr),
    .mem_wdata(mem_wdata),
    .mem_wstrb(mem_wstrb),
    .mem_rdata(psram_rdata),
    .mem_ready(psram_ready),
    .mem_valid(psram_valid)
);

wire [3:0] RAM_WE;
assign RAM_WE = ((mem_addr[16:0] > 17'h0ffff)&&(mem_addr[16:0] < 17'h14000)) ? mem_wstrb : 4'h0;
wire [31:0] RAM_RDATA;

RAM RAM_u0(
    .dout(RAM_RDATA[7:0]), //output [7:0] dout
    .clk(clk), //input clk
    .oce(1'b1), //input oce
    .ce(1'b1), //input ce
    .reset(~resetn), //input reset
    .wre(RAM_WE[0]), //input wre
    .ad(mem_addr[13:2]), //input [11:0] ad
    .din(mem_wdata[7:0]) //input [7:0] din
);
RAM RAM_u1(
    .dout(RAM_RDATA[15:8]), //output [7:0] dout
    .clk(clk), //input clk
    .oce(1'b1), //input oce
    .ce(1'b1), //input ce
    .reset(~resetn), //input reset
    .wre(RAM_WE[1]), //input wre
    .ad(mem_addr[13:2]), //input [11:0] ad
    .din(mem_wdata[15:8]) //input [7:0] din
);
RAM RAM_u2(
    .dout(RAM_RDATA[23:16]), //output [7:0] dout
    .clk(clk), //input clk
    .oce(1'b1), //input oce
    .ce(1'b1), //input ce
    .reset(~resetn), //input reset
    .wre(RAM_WE[2]), //input wre
    .ad(mem_addr[13:2]), //input [11:0] ad
    .din(mem_wdata[23:16]) //input [7:0] din
);
RAM RAM_u3(
    .dout(RAM_RDATA[31:24]), //output [7:0] dout
    .clk(clk), //input clk
    .oce(1'b1), //input oce
    .ce(1'b1), //input ce
    .reset(~resetn), //input reset
    .wre(RAM_WE[3]), //input wre
    .ad(mem_addr[13:2]), //input [11:0] ad
    .din(mem_wdata[31:24]) //input [7:0] din
);

reg [1:0] ram_cnt;
always @(posedge clk or negedge resetn) begin
        if(!resetn)begin
            ram_cnt <= 2'b00;
            out_byte <= 8'h0;
            mem_ready_r0 <= 0;
        end
        else begin
            if(!mem_valid)begin
                ram_cnt <= 2'b00;
                mem_ready_r0 <= 1'b0;
            end
		    
            else if (resetn && mem_valid && !mem_ready) begin

                    if(mem_addr == 32'h1000_0000) begin
                        if(|mem_wstrb) begin
                            out_byte <= mem_wdata;
                            mem_ready_r0 <= 1'b1;
                        end
                        else begin
                            mem_rdata_r0 <= {24'h0, out_byte[7:0]};
                            mem_ready_r0 <= 1'b1;
                            /*if(ram_cnt == 2'b01)begin
                                mem_rdata_r0 <= {24'h0, out_byte[7:0]};
                                mem_ready_r0 <= 1'b1;
                            end
                            else begin
                                ram_cnt <= ram_cnt + 1'b1;
                                mem_ready_r0 <= mem_ready_r0;
                            end*/
                        end
                    end
                    else if((mem_addr[16:0] > 17'h0ffff)&&(mem_addr[16:0] < 17'h14000)) begin
                        if(|mem_wstrb) begin
                            mem_ready_r0 <= 1'b1;
                        end
                        else begin
                            if(ram_cnt == 2'b01)begin
                                mem_rdata_r0 <= RAM_RDATA;
                                mem_ready_r0 <= 1'b1;
                            end
                            else begin
                                ram_cnt <= ram_cnt + 1'b1;
                                mem_ready_r0 <= mem_ready_r0;
                            end
                        end
                    end
                    else if((mem_addr >= 32'h80_0000)&&(mem_addr < 32'h100_0000)) begin
                        
                    end
                    else begin
                        mem_rdata_r0 <= {24'h0, out_byte[7:0]};
                        mem_ready_r0 <= 1'b1;
                    end
            end
        end
	end
endmodule
